package com.yizisu.basemvvm.utils

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.TransitionDrawable
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicBlur
import android.text.*
import android.text.method.HideReturnsTransformationMethod
import android.text.method.LinkMovementMethod
import android.text.method.PasswordTransformationMethod
import android.text.style.AbsoluteSizeSpan
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.view.*
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.yizisu.basemvvm.app
import com.yizisu.basemvvm.logI
import com.yizisu.basemvvm.view.GestureDetectorHelper

/**
 * 若红楼梦空，亦初心不变
 * 作者：kotle
 * 包名：com.yizisu.basemvvm.utils
 * 时间：2019/1/17 23:47
 * 描述：view扩展方法
 */
/**
 * 获取颜色值
 */
fun Any.getResColor(@ColorRes colorRes: Int): Int {
    return when (this) {
        is Context -> {
            ContextCompat.getColor(this, colorRes)
        }
        is Fragment -> {
            ContextCompat.getColor(context ?: app, colorRes)
        }
        else -> {
            ContextCompat.getColor(app, colorRes)
        }
    }
}

/**
 * 获取字符串
 */
fun Any.getResString(@StringRes stringRes: Int): CharSequence {
    return when (this) {
        is Context -> {
            getString(stringRes)
        }
        is Fragment -> {
            (context ?: app).getString(stringRes)
        }
        else -> {
            app.getString(stringRes)
        }
    }
}

/**
 * 获取图片
 */
fun Any.getResDrawable(@DrawableRes drawableRes: Int): Drawable? {
    return when (this) {
        is Context -> {
            ContextCompat.getDrawable(this, drawableRes)
        }
        is Fragment -> {
            ContextCompat.getDrawable(context ?: app, drawableRes)
        }
        else -> {
            ContextCompat.getDrawable(app, drawableRes)
        }
    }
}

/**
 * 资源文件的bool值
 */
fun Any.getResBool(@BoolRes boolRes: Int): Boolean? {
    return try {
        when (this) {
            is Context -> {
                this.resources.getBoolean(boolRes)
            }
            is Fragment -> {
                (this.context ?: app).resources.getBoolean(boolRes)
            }
            else -> {
                app.resources.getBoolean(boolRes)
            }
        }
    } catch (e: Throwable) {
        e.printStackTrace()
        null
    }
}

/**
 * 资源文件的像素值（dp->px）
 * 返回绝对像素 px
 *  getDimension()是基于当前DisplayMetrics进行转换，获取指定资源id对应的尺寸。
 *                文档里并没说这里返回的就是像素，要注意这个函数的返回值是float，像素肯定是int。
 *  getDimensionPixelSize()与getDimension()功能类似，
 *                不同的是将结果转换为int，并且小数部分四舍五入。
 *  getDimensionPixelOffset()与getDimension()功能类似，
 *                不同的是将结果转换为int，并且偏移转换（offset conversion，函数命名中的offset是这个意思）
 *                 是直接截断小数位，即取整（其实就是把float强制转化为int，注意不是四舍五入哦
 */
fun Any.getResDimension(@DimenRes dimenRes: Int): Float {
    return try {
        when (this) {
            is Context -> {
                this.resources.getDimension(dimenRes)
            }
            is Fragment -> {
                (this.context ?: app).resources.getDimension(dimenRes)
            }
            else -> {
                app.resources.getDimension(dimenRes)
            }
        }
    } catch (e: Throwable) {
        e.printStackTrace()
        0f
    }
}

fun Any.getResDimensionPixelSize(@DimenRes dimenRes: Int): Int {
    return try {
        when (this) {
            is Context -> {
                this.resources.getDimensionPixelSize(dimenRes)
            }
            is Fragment -> {
                (this.context ?: app).resources.getDimensionPixelSize(dimenRes)
            }
            else -> {
                app.resources.getDimensionPixelSize(dimenRes)
            }
        }
    } catch (e: Throwable) {
        e.printStackTrace()
        0
    }
}

/**
 * 设置文本颜色
 */
infix fun TextView.setTextColorByRes(@ColorRes colorRes: Int) {
    setTextColor(getResColor(colorRes))
}

/**
 * 设置textView从资源文件
 */
infix fun TextView.textFrom(@StringRes strRes: Int) {
    text = try {
        this.context.getText(strRes)
    } catch (e: Throwable) {
        strRes.toString()
    }
}

/**
 * 设置textView从资源文件
 */
infix fun TextView.textFrom(str: CharSequence?) {
    text = str
}

data class SpanBean(
    var text: String?,
    var textColor: Int? = null,
    var textSize: Int? = null,
    var textClickListener: NoUnderLineClickableSpan? = null,
    var spanWhatList: MutableList<Any>? = null
)

infix fun TextView.textFromSpanBean(textList: MutableList<SpanBean>) {
    val ssb = SpannableStringBuilder()
    textList.forEach {
        if (it.text != null) {
            val sbText = SpannableStringBuilder(it.text)
            /**
             * 文字大小
             */
            it.textSize?.let { textSize ->
                sbText.setSpan(
                    AbsoluteSizeSpan(textSize, true),
                    0,
                    it.text!!.length,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                )
            }
            /**
             * 文字颜色
             */
            it.textColor?.let { textColor ->
                sbText.setSpan(
                    ForegroundColorSpan(textColor),
                    0,
                    it.text!!.length,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                )
            }
            /**
             * 文字点击
             */
            it.textClickListener?.let { listener ->
                //这个一定要记得设置，不然点击不生效
                movementMethod = LinkMovementMethod.getInstance()
                sbText.setSpan(listener, 0, it.text!!.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            }
            /**
             * 其他span
             */
            it.spanWhatList?.forEach { what ->
                sbText.setSpan(what, 0, it.text!!.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            }
            ssb.append(sbText)
        }
    }
    text = ssb
}

abstract class NoUnderLineClickableSpan : ClickableSpan() {
    override fun updateDrawState(ds: TextPaint) {
        super.updateDrawState(ds)
        ds.isUnderlineText = false
    }
}

/**
 * glide加载图片监听
 */
class SimpleGlideLoadListener<TranscodeType>(private val onResourceReady: Function2<TranscodeType?, GlideException?, Unit>) :
    RequestListener<TranscodeType> {
    override fun onLoadFailed(
        e: GlideException?,
        model: Any?,
        target: Target<TranscodeType>?,
        isFirstResource: Boolean
    ): Boolean {
        onResourceReady.invoke(null, e)
        return false
    }

    override fun onResourceReady(
        resource: TranscodeType,
        model: Any?,
        target: Target<TranscodeType>?,
        dataSource: DataSource?,
        isFirstResource: Boolean
    ): Boolean {
        onResourceReady.invoke(resource, null)
        return false
    }
}

/**
 * 设置视频预览画面
 * 必须要先缓存下来
 */
//fun ImageView.setVideoFrameGlide(url: String?, time: Long) {
//    url ?: return
//    Glide.with(context.applicationContext)
//        .setDefaultRequestOptions(
//            RequestOptions()
//                //这里限制了只从缓存读取
//                .onlyRetrieveFromCache(true)
//                .frame(1000 * time)
//                .override(413, 275)
//                .dontAnimate()
//                .placeholder(drawable)
//                .centerCrop()
//        )
//        .load(url)
//        .into(this)
//}

/**
 * 通过Glide设置图片
 * 用自己的本身的可能导致内存泄漏
 * radius圆角半径，0 位方形，小于0 是圆 ，大于0 就是圆角的读书
 */
const val GLIDE_LOAD_RADIUS_NORMAL = 0
const val GLIDE_LOAD_RADIUS_CIRCLE = -1

/**
 * 获取默认的加载选项
 */
fun getDefaultOption(radius: Int): RequestOptions {
    return when {
        radius < 0 -> {
            RequestOptions.bitmapTransform(CircleCrop())
        }
        radius == 0 -> {
            RequestOptions()
        }
        else -> {
            RequestOptions.bitmapTransform(RoundedCorners(radius))
        }
    }
}

fun RequestManager.startLoad(
    view: ImageView,
    obj: Any?,
    replace: Any? = null,
    radius: Int = 0,
    requestOptions: RequestOptions? = null,
    transition: DrawableTransitionOptions? = null
) {
    if (obj == null && replace == null) {
        view.setImageDrawable(null)
        this.clear(view)
    } else {
        this.load(obj ?: replace).apply {
            val oldDrawable = view.drawable.safeGet<BitmapDrawable>()
            if (oldDrawable?.bitmap?.isRecycled == false) {
                placeholder(view.drawable)
            } else {
                placeholder(null)
            }
            apply(requestOptions ?: getDefaultOption(radius))
            if (replace is Int) {
                error(replace)
            }
            if (transition != null) {
                transition(transition)
            } else {
                dontAnimate()
            }
            into(view)
        }
    }
}

fun ImageView.setImageGlide(
    obj: Any?/*需要显示的对象*/,
    replace: Any? = null/*如果目标为null，则显示这个*/,
    radius: Int = GLIDE_LOAD_RADIUS_NORMAL/*设置图片圆角，像素是px*/,
    requestOptions: RequestOptions? = null/*设置自己的加载选项*/,
    transition: DrawableTransitionOptions? = null
) {
    Glide.with(this).startLoad(this, obj, replace, radius, requestOptions, transition)
}

fun Fragment.setImageGlide(
    view: ImageView/*图像载体*/,
    obj: Any?/*需要显示的对象*/,
    replace: Any? = null/*如果目标为null，则显示这个*/,
    radius: Int = GLIDE_LOAD_RADIUS_NORMAL/*设置图片圆角，像素是px*/,
    requestOptions: RequestOptions? = null/*设置自己的加载选项*/,
    transition: DrawableTransitionOptions? = null
) {
    Glide.with(this).startLoad(view, obj, replace, radius, requestOptions, transition)
}

fun AppCompatActivity.setImageGlide(
    view: ImageView/*图像载体*/,
    obj: Any?/*需要显示的对象*/,
    replace: Any? = null/*如果目标为null，则显示这个*/,
    radius: Int = GLIDE_LOAD_RADIUS_NORMAL/*设置图片圆角，像素是px*/,
    requestOptions: RequestOptions? = null/*设置自己的加载选项*/,
    transition: DrawableTransitionOptions? = null
) {
    Glide.with(this).startLoad(view, obj, replace, radius, requestOptions, transition)
}

fun Context.setImageGlide(
    view: ImageView/*图像载体*/,
    obj: Any?/*需要显示的对象*/,
    replace: Any? = null/*如果目标为null，则显示这个*/,
    radius: Int = GLIDE_LOAD_RADIUS_NORMAL/*设置图片圆角，像素是px*/,
    requestOptions: RequestOptions? = null/*设置自己的加载选项*/,
    transition: DrawableTransitionOptions? = null
) {
    Glide.with(this).startLoad(view, obj, replace, radius, requestOptions, transition)
}


/**
 * 从一个url加载图片到view
 */
@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
fun ImageView.setImageFromNet(url: String?, activity: Context) {
    activity.setImageGlide(this, url)
}

@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
fun ImageView.setImageFromNet(url: String?, activity: Activity) {
    activity.setImageGlide(this, url)
}

/**
 * 从一个url加载圆形图片到view
 */
@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
infix fun ImageView.setCircleImageFromNet(url: String?) {
    setImageGlide(url, radius = GLIDE_LOAD_RADIUS_CIRCLE)
}

/**
 * 加载圆角图片
 */
@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
fun ImageView.setCircleImageFromNet(url: String?, radius: Int) {
    setImageGlide(url, dip(radius))
}

/**
 * 加载圆角图片
 */
@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
fun ImageView.setCircleImageFromRes(resId: Int?, radius: Int) {
    setImageGlide(resId, dip(radius))
}

/**
 * 从资源文件加载圆形图片到view
 */
@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
infix fun ImageView.setCircleImageFromRes(resId: Int?) {
    setImageGlide(resId, radius = GLIDE_LOAD_RADIUS_CIRCLE)
}
/**
 * 从一个url加载高斯模糊
 * 需要引入第三方库
 */
/*infix fun ImageView.setBlurImageFromNet(url: String?) {
    if (url == null) {
        setImageDrawable(null)
    } else {
        Glide.with(this)
                .load(url)
                .apply(RequestOptions
                        .bitmapTransform(BlurTransformation(13))
                        .diskCacheStrategy(DiskCacheStrategy.ALL))
                .into(this)

    }
}*/

/**
 * 从一个url加载图片到view
 */
@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
infix fun ImageView.setImageFromNet(url: String?) {
    setImageGlide(url)
}


/**
 * 从一个url加载图片到view
 */
@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
fun ImageView.setImageFromNet(url: String?, width: Int, height: Int) {
    setImageGlide(
        url, requestOptions = RequestOptions()
            .diskCacheStrategy(DiskCacheStrategy.ALL)
            .override(width, height)
    )
}

/**
 * 清除加载的图片
 */
@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
infix fun ImageView.clearFromActivity(activity: Activity) {
    setImageGlide(null)
}

/**
 * 清除加载的图片
 */
@Deprecated("方法命名统一", ReplaceWith("setImageGlide"))
infix fun ImageView.clearFromContext(context: Context) {
    setImageGlide(null)
}

/**
 * view隐藏
 */
fun View?.gone() {
    this ?: return
    if (visibility != View.GONE) {
        visibility = View.GONE
    }
}

/**
 * view可见
 */
fun View?.visible() {
    this ?: return
    if (visibility != View.VISIBLE) {
        visibility = View.VISIBLE
    }
}

/**
 * view隐藏
 */
fun View?.invisible() {
    this ?: return
    if (visibility != View.INVISIBLE) {
        visibility = View.INVISIBLE
    }
}

/**
 * view是否可见
 */
fun View.isVisible(): Boolean {
    return visibility == View.VISIBLE
}

/**
 * view是否可见
 */
fun View.isInVisible(): Boolean {
    return visibility == View.INVISIBLE
}

/**
 * view是否隐藏
 */
fun View.isGone(): Boolean {
    return visibility == View.GONE
}

/**
 * dp2px
 */
fun dip(value: Int): Int {
    return (value * ScreenAdaptation.density).toInt()
}

/**
 * dp2px
 */
fun dip(value: Float): Float {
    return value * ScreenAdaptation.density
}


fun ViewGroup.inflate(@LayoutRes id: Int, isAttach: Boolean = false): View {
    return LayoutInflater.from(this.context).inflate(id, this, isAttach)
}

/**
 * 设置textView从资源文件
 */
@SuppressLint("RtlHardcoded")
fun TextView.setIcon(
    @DrawableRes drawableRes: Int?, gravity: Int = Gravity.START,
    drawablePaddingDip: Int = -1
) {
    if (drawableRes == null) {
        setCompoundDrawables(null, null, null, null)
        return
    }
    val drawable = context.getResDrawable(drawableRes)
    if (drawable == null) {
        setCompoundDrawables(null, null, null, null)
        return
    }
    drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
    if (drawablePaddingDip >= 0) {
        compoundDrawablePadding = dip(drawablePaddingDip)
    }
    when (gravity) {
        Gravity.TOP -> {
            setCompoundDrawables(null, drawable, null, null)
        }
        Gravity.BOTTOM -> {
            setCompoundDrawables(null, null, null, drawable)
        }
        Gravity.END, Gravity.RIGHT -> {
            setCompoundDrawables(null, null, drawable, null)
        }
        else -> {
            setCompoundDrawables(drawable, null, null, null)
        }
    }
}

/**
 * 监听文本输入之后
 */
fun EditText.afterTextChanged(onAfterTextChanged: Function1<Editable?, Unit>) {
    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
            onAfterTextChanged.invoke(s)
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

    })
}

/**
 * 文本输入之前监听
 */
fun EditText.beforeTextChanged(beforeTextChanged: (s: CharSequence?, start: Int, count: Int, after: Int) -> Unit) {
    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            beforeTextChanged.invoke(s, start, count, after)
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

    })
}

/**
 * 文本改变监听
 */
fun EditText.onTextChanged(onTextChanged: (s: CharSequence?, start: Int, before: Int, count: Int) -> Unit) {
    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            onTextChanged.invoke(s, start, before, count)
        }

    })
}

fun EditText?.onSearch(isHideKeyboard: Boolean = true, search: (text: String) -> Unit) {
    this?.imeOptions = EditorInfo.IME_ACTION_SEARCH
    this?.setSingleLine()
    this?.setOnEditorActionListener { v, actionId, event ->
        if (actionId == EditorInfo.IME_ACTION_SEARCH) {
            val ctx = context
            if (isHideKeyboard && ctx is Activity) {
                ctx.hiddenKeyboard()
            }
            search.invoke(v.text.toString())
            return@setOnEditorActionListener true
        }
        return@setOnEditorActionListener true
    }
}

/**
 * 密码可见不可见
 */
fun EditText.visiblePassword(visible: Boolean) {
    transformationMethod = if (visible) {
        //选择状态 显示明文--设置为可见的密码
        //mEtPassword.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
        HideReturnsTransformationMethod.getInstance()
    } else {
        //默认状态显示密码--设置文本 要一起写才能起作用 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
        //mEtPassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
        PasswordTransformationMethod.getInstance()
    }
    setSelection(text.count())
}

/**
 * 设置双击监听
 * 注意GestureDetectorHelper对于同一个view对象只能创建一次
 * 如果不想响应单击，可以这样使用
 *  @sample{
 *   GestureDetectorHelper(view, true).apply {
 *   setOnDoubleClickListener {
 *     //双击
 *      }
 *      setOnClickListener {
 *       //单击
 *    }
 *   }
 *  }
 */
fun View.setOnDoubleClickListener(l: Function1<MotionEvent?, Unit>) {
    GestureDetectorHelper(this, true).setOnDoubleClickListener(l)
}